﻿using AIVision.Model.MachineModels;
using AIVision.Model.EntityModels;
using AIVision.Model.UIModels;
using AIVision.PLC.LiWi;
using ImTools;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AIVision.PLC.MachineModule
{
    public class ZhuanTai
    {
        private readonly ZhuanTaiStatusModel zhuanTaiStatus;
        private readonly IEventAggregator eventAggregator;
        private readonly MachineStatusModel machineStatus;
        private IntPtr _handle;
        private PLCConfigDto plcConfig;

        public bool ShangLiaoXH
        {
            get
            {
                uint in7 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 7, ref in7);
                zhuanTaiStatus.ShangLiaoXH = in7 == 1;
                return in7 == 1;
            }
        }

        public bool OKLiaoXH
        {
            get
            {
                uint in8 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 8, ref in8);
                zhuanTaiStatus.OKLiaoXH = in8 == 1;
                return in8 == 1;
            }
        }
        public bool NGLiaoXH
        {
            get
            {
                uint in9 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 9, ref in9);
                zhuanTaiStatus.NGLiaoXH = in9 == 1;
                return in9 == 1;
            }
        }
        public bool YuanDianXH
        {
            get
            {
                uint in4 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 4, ref in4);
                //zhuanTaiStatus.NGLiaoXH = in9 == 1;
                return in4 == 1;
            }
        }
        private bool runStatus;
        public bool ServoRunXH
        {
            get
            {
                int runFlag = -1;
                Shell.PMC_GetIfIdle(_handle, 0, ref runFlag);
                zhuanTaiStatus.ServoRunXH = runFlag == 0;
                return runFlag == 0;
            }
        }

        public bool PPUFangLiaoXH
        {
            get
            {
                uint in3 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 3, ref in3);
                return in3 == 1;
            }
        }
        public bool CheHeQuLiaoUpXH
        {
            get
            {
                uint in13 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 13, ref in13);
                return in13 == 1;
            }
        }
        public float DPos {
            get
            {
                float dpos = 0;
                Shell.PMC_GetDpos(_handle, 0, ref dpos);
                return dpos;
            }
        }

        
        public Task RunTask { get; set; } = new Task(() => { });
        Stopwatch runWatch = new System.Diagnostics.Stopwatch();
        public ZhuanTai(ZhuanTaiStatusModel zhuanTaiStatus,IEventAggregator eventAggregator,MachineStatusModel machineStatus) 
        {
            this.zhuanTaiStatus = zhuanTaiStatus;
            this.eventAggregator = eventAggregator;
            this.machineStatus = machineStatus;
        }
        public void Init(IntPtr _handle, PLCConfigDto plcConfig)
        {
            this._handle = _handle;
            this.plcConfig = plcConfig;
        }

        public void ResetLocationAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(ResetLocation, CTS.Token);
                RunTask.Start();
            }
        }
        public void ResetLocation()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                int ret0 = Shell.PMC_SetAtype(_handle, 0, 1); // 设置轴类型为 1 
                ret0 += Shell.PMC_SetInvertStep(_handle, 0, 1); //设置脉冲输出模式
                ret0 += Shell.PMC_SetUnits(_handle, 0, 1); // 设置脉冲 
                Shell.PMC_SetAxisEnable(_handle, 0, 1); //使能开

                Shell.PMC_SetSpeed(_handle, 0, 3600);
                Shell.PMC_Single_Vmove(_handle, 0, 1);
                timeout = 0;
                while (!YuanDianXH)
                    WaitTimeout(10000);
                Shell.PMC_Single_Cancel(_handle, 0, 3);
                Shell.PMC_SetSpeed(_handle, 0, 180);
                Shell.PMC_Single_Vmove(_handle, 0, 1);
                timeout = 0;
                while (YuanDianXH)
                    WaitTimeout(10000);
                Shell.PMC_Single_Cancel(_handle, 0, 3);
                ret0 += Shell.PMC_SetSpeed(_handle, 0, 3600); // 设置轴 0 速度为 200units/s 

                ret0 = Shell.PMC_SetDpos(_handle, 0, 0); // 轴指令位置清 0 
                ret0 += Shell.PMC_SetMpos(_handle, 0, 0); // 编码器反馈位置清 0 
                Shell.PMC_Single_Move(_handle, 0, plcConfig.ZhuanTaiInitOffset);
                timeout = 0;
                while (DPos != plcConfig.ZhuanTaiInitOffset)
                    WaitTimeout(10000);
                ret0 = Shell.PMC_SetDpos(_handle, 0, 0); // 轴指令位置清 0 
                ret0 += Shell.PMC_SetMpos(_handle, 0, 0); // 编码器反馈位置清 0 
                ret0 += Shell.PMC_SetSpeed(_handle, 0, plcConfig.ZhuanTaiRunSpeed); // 设置轴 0 速度为 200units/s 
                ret0 += Shell.PMC_SetAccel(_handle, 0, plcConfig.ZhuanTaiAccl); // 设置轴 0 加速度为 2000units/s/s 
                ret0 += Shell.PMC_SetDecel(_handle, 0, plcConfig.ZhuanTaiAccl); // 设置轴 0 减速度为 2000units/s/s 
                zhuanTaiStatus.Location = (int)Math.Floor(DPos / plcConfig.ZhuanTaiStep) + 1;
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 0, 3);
            }
        }
        public void RunAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH && machineStatus.ResetLocationStatus)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(Run, CTS.Token);
                RunTask.Start();
            }
        }
        public void Run()
        {
            if (machineStatus.EmergencyStopXH && !machineStatus.ResetLocationStatus)
                return;
            try
            {
                if (!PPUFangLiaoXH && CheHeQuLiaoUpXH && !machineStatus.EmergencyStopXH)
                {
                    Task.Delay(plcConfig.ZhuanStartDelay).Wait();
                    Shell.PMC_Single_Move(_handle, 0, plcConfig.ZhuanTaiStep);
                    timeout = 0;
                    while (ServoRunXH)
                        WaitTimeout(5000);
                    Task.Delay(plcConfig.ZhuanStopDelay).Wait();
                    zhuanTaiStatus.Location = (int) Math.Floor(DPos / plcConfig.ZhuanTaiStep) +1;
                    if(zhuanTaiStatus.Location > 8)
                    {
                        Shell.PMC_SetDpos(_handle, 0, 0); // 轴指令位置清 0 
                        Shell.PMC_SetMpos(_handle, 0, 0); // 编码器反馈位置清 0 
                        zhuanTaiStatus.Location = 1;
                    }

                    runWatch.Stop();
                    machineStatus.RunSpeed = runWatch.ElapsedMilliseconds;
                    runWatch.Restart();
                }
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 0, 3);
            }
        }


        public void MonitorStatus()
        {
            float dpos = 0, mpos = 0, pfvalue = 0;
            Shell.PMC_GetDpos(_handle, 0, ref dpos);
            Shell.PMC_GetMpos(_handle, 0, ref mpos);
            Shell.PMC_GetMspeed(_handle, 0, ref pfvalue);
            zhuanTaiStatus.DPos = dpos;
            zhuanTaiStatus.MPos = mpos;
            zhuanTaiStatus.Speed = pfvalue;
            zhuanTaiStatus.Location = (int)Math.Floor(DPos / plcConfig.ZhuanTaiStep) + 1;
            if (zhuanTaiStatus.Location > 8)
            {
                zhuanTaiStatus.Location = 1;
            }
            var v = ShangLiaoXH;
            v = OKLiaoXH;
            v = NGLiaoXH;
            v = ServoRunXH;
        }


        #region WaitTimeout
        public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
        public delegate void TimeOutDelegate();
        private int timeout = 0;
        private void WaitTimeout(int waitTime, string msg = "", TimeOutDelegate timeOutDelegate = null)
        {
            // 检查是否请求取消
            CTS.Token.ThrowIfCancellationRequested();
            Task.Delay(1).Wait();
            timeout += 1;
            if (timeout > waitTime)
            {
                CTS.Cancel();
                if (timeOutDelegate != null)
                    timeOutDelegate();
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"等待超时:{msg}", "Red"));
            }
        }
        #endregion
    }
}
